package com.tc.quartz.server.job.base;


import com.tc.quartz.server.core.IPaymentQuartzService;
import com.tc.quartz.server.core.StatusEnum;
import com.tc.quartz.server.exception.JobRunException;
import com.tc.quartz.util.QrtzUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * job基类
 * @author yongjin.ye
 *
 */
public abstract class BaseJob extends QuartzJobBean {
	
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	private IPaymentQuartzService paymentQuartzService;
	protected StringBuffer jobRunLog = null;//要记录日志的对象
	
	/**
	 * 定时器监控，记录定时任务日志
	 */
	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException{
		long startTime = System.currentTimeMillis();
		String jobName = context.getJobDetail().getKey().getName();
		log.info(String.format("-------------定时任务【%s】运行开始-------------", jobName));
		//初始化变量
		this.paymentQuartzService = this.getSpringBean(IPaymentQuartzService.class);
		this.jobRunLog = new StringBuffer();
		long logId = 0;
		String resultCode = StatusEnum.SUCCESS.getValue();
		String resultMsg = StatusEnum.SUCCESS.getDesc();
		try {
			//记录运行日志
			logId = this.paymentQuartzService.insertJobRunLog(context, startTime);
			Object result = this.doExecute(context);
			log.info("定时任务[{}]执行完毕，执行结果：{}", jobName, result);
			this.jobRunLog.append(String.format("执行结果：%s \r\n", result));
		}catch (DuplicateKeyException e){
			log.error("记录日志时主键冲突", e);
			try {
				this.paymentQuartzService.insertJobRunLog(context, startTime, true);
			} catch (Exception e1) {
				log.error("记录重复运行日志异常", e1);
			}
		} catch (JobRunException e){
			log.error("定时器运行JOB异常", e);
			resultCode = e.getCode();
			resultMsg = e.getMessage();
			this.jobRunLog.append(String.format("\r\n运行异常信息:%s", ExceptionUtils.getStackTrace(e)));
		} catch (Exception e) {
			log.error("定时器运行JOB异常", e);
			resultCode = StatusEnum.ERR_OTHER.getValue();
			resultMsg = StringUtils.isBlank(e.getMessage()) ? StatusEnum.ERR_OTHER.getDesc() : e.getMessage();
			this.jobRunLog.append(String.format("\r\n运行异常信息:%s", ExceptionUtils.getStackTrace(e)));
		} finally {
			boolean triggerNextJob = this.triggerNextJob(context, resultCode);
			if (!triggerNextJob) {
				resultCode = StatusEnum.ERR_TRIGGER_NEXT_jOB.getValue();
				resultMsg = StatusEnum.ERR_TRIGGER_NEXT_jOB.getDesc();
			}
			//更新运行日志
			long endTime = System.currentTimeMillis();
			int ucount = this.paymentQuartzService.updateJobRunLog(logId, resultCode, resultMsg, jobRunLog.toString(), endTime);
			if (ucount == 0) {
				log.error("更新日志失败，请求参数：logId={}, resultCode={}, resultMsg={}, remark={}", logId, resultCode, resultMsg, jobRunLog.toString());
			}
			log.info(String.format("-------------定时任务【%s】运行结束, 耗时：%s-------------" , jobName, (endTime - startTime)));
		}
		//清空对象
		this.jobRunLog = null;
		resultCode = null;
		resultMsg = null;
	}
	
	private boolean triggerNextJob(JobExecutionContext context, String resultCode) {
		try {
			String nextjobstr = context.getJobDetail().getJobDataMap().getString(IPaymentQuartzService.TRIGGER_NEXT_JOB);
			if (StringUtils.isBlank(nextjobstr)) {
				return true;
			}
			//NEXT_JOB=0000,9999|testJob
			String codes = nextjobstr.split("\\|")[0];
			if ("0".equals(codes) || codes.indexOf(resultCode) >= 0) {
				String triggerResult = this.paymentQuartzService.triggerNextJob(context);
				this.jobRunLog.append(String.format("\r\n成功触发NEXT_JOB=[%s], resultCode=%s, 触发结果=%s", nextjobstr, resultCode, triggerResult));
			} else {
				this.jobRunLog.append(String.format("\r\n未能触发NEXT_JOB=[%s], resultCode=%s", nextjobstr, resultCode));
			}
			return true;
		} catch (Exception e) {
			this.jobRunLog.append(String.format("\r\n触发nextjob异常:%s", ExceptionUtils.getStackTrace(e)));
			log.error("触发nextjob异常", e);
		} 
		return false;
	}
	
	/**
	 * 子类需要实现的方法,job的具体工作
	 * @param arg0
	 */
	protected abstract Object doExecute(JobExecutionContext context) throws Exception;


	/**
	 * 获取springBean方法
	 * @param beanName
	 * @return
	 */
	protected <T> T getSpringBean (String beanName) {
		return QrtzUtil.getBean(beanName);
	}
	
	/**
	 * 获取springBean方法
	 * @param beanName
	 * @return
	 */
	protected <T> T getSpringBean (Class<?> clazz) {
		return QrtzUtil.getBean(clazz);
	}
	
	
}
